#include <string>
#include <map>
#include <vector>

#ifndef ELEC_AS_REGISTRY_HH
#define ELEC_AS_REGISTRY_HH

/* DESCRIPTION:
 * ------------
 * The definition of the course structure. Each course has a course id, name and
 * the number of credits awarded for the course.
 *
 * Two courses are equal if the course ids of those courses are equal.
 */
typedef struct Course_s {
	std::string courseId;
	std::string courseName;
	size_t credits;
} Course;


/* DESCRIPTION:
 * ------------
 * The definition of the entry structure. Each entry has a course associated
 * with it and a grade received for the course.
 *
 * Two entries are equal if the course ids and grades of the two entries are
 * the same.
 */
typedef struct Entry_s {
	Course course;
	size_t grade;
} Entry;


/* DESCRIPTION:
 * ------------
 * The function adds one entry, for the parameter student id, in to the
 * parameter registry. If the student id doesn't exist in the registry
 * it should be added there along with the entry.
 *
 * If the student already has an entry for the same course, the entry
 * with the better grade should be chosen to the registry. The entry
 * should replace the existing one, and thus be in the same place as
 * the old entry in the "transcript".
 *
 * Courses are identified solely by their course ids.
 *
 * PARAMETERS:
 * ------------
 * std::map<std::string, std::vector<Entry>>& registry: the registry where to
 * add the entry for the corresponding student id.
 *
 * const std::string& studentId: the student to add the entry for.
 *
 * const Entry& entry: entry to be added.
 *
 * RETURNS:
 * ------------
 * Nothing.
 */
void addEntry(std::map<std::string, std::vector<Entry>>& registry, const std::string& studentId, const Entry& entry);


/* DESCRIPTION:
 * ------------
 * Removes the parameter entry from the parameter student. If there is no such
 * entry for the student or no such student the function does nothing.
 *
 * Remember that two entries are equal if the course id's and the grades are
 * equal.
 *
 * PARAMETERS:
 * ------------
 * std::map<std::string, std::vector<Entry>>& registry: the registry where to
 * remove the entry from the corresponding student id.
 *
 * const std::string& studentId: the student to remove the entry from.
 *
 * const Entry& entry: entry to be removed.
 *
 * RETURNS:
 * ------------
 * Nothing.
 */
void removeEntry(std::map<std::string, std::vector<Entry>>& registry, const std::string& studentId, const Entry& entry);


/* DESCRIPTION:
 * ------------
 * Prints the transcript (report of all the entries) for the parameter student
 * id. All the output is printed to standard output (std::cout).
 *
 * The output format is as follows:
 *
 * Transcript for <student id>:
 * <course id> <course name> <course credits> <grade>
 * .
 * .
 * <course id> <course name> <course credits> <grade>
 *
 * If the student isn't in the registry the output is simply:
 *
 * No student with id <student id> was found in the registry.
 *
 * PARAMETERS:
 * ------------
 * const std::map<std::string, std::vector<Entry>>& registry: the registry with
 * all the entries for each student.
 *
 * const std::string& studentId: the student id.
 *
 * RETURNS:
 * ------------
 * Nothing.
 */
void printTranscript(const std::map<std::string, std::vector<Entry>>& registry, const std::string& studentId);


/* DESCRIPTION:
 * ------------
 * The function collects all the failed entries (entries with grade 0) from the
 * parameter registry in to a single vector and returns it.
 *
 * Hint: to get the job done easily use algorithms and predicates, for example
 * copy_if (C++0x feature) might be useful.
 *
 * PARAMETERS:
 * ------------
 * std::map<std::string, std::vector<Entry>>& registry: the registry.
 *
 * RETURNS:
 * ------------
 * A vector containing the failed entries in the registry.
 */
std::vector<Entry> getFailed(const std::map<std::string, std::vector<Entry>>& registry);


/* DESCRIPTION:
 * ------------
 * The function calculates the total credits for one student. If the student is
 * not found in the parameter registry the function returns 0.
 *
 * Note that also the credits of entries with grade 0 are included in the
 * returned sum.
 *
 * Hint: accumulate
 *
 * PARAMETERS:
 * ------------
 * const std::map<std::string, std::vector<Entry>>& registry: the registry
 * containing the entries for all of the students.
 *
 * const std::string& studentId: the student id of the student.
 *
 * RETURNS:
 * ------------
 * The total number of credits for the student or 0 if the student isn't in the
 * registry.
 */
size_t calculateTotalCredits(const std::map<std::string, std::vector<Entry>>& registry, const std::string& studentId);


/* DESCRIPTION:
 * ------------
 * The function calculates the weighted average for the parameter student id. If
 * no such student exists in the parameter registry the function returns 0.
 *
 * Weighted average is calculated by first calculating and adding up
 * grade*credits for each entry and then dividing the resulting sum by the number
 * of total credits for the student.
 *
 * Hint: accumulate, calculateTotalCredits
 *
 * PARAMETERS:
 * ------------
 * const std::map<std::string, std::vector<Entry>>& registry: the registry
 * containing the entries for all of the students.
 *
 * const std::string& studentId: the student id of the student.
 *
 * RETURNS:
 * ------------
 * The weighted average for the student or 0 if the student isn't in the
 * registry.
 */
double calculateAverage(const std::map<std::string, std::vector<Entry>>& registry, const std::string& studentId);

#endif
